﻿/***************************************************************
 * 开发人员：网魂小兵@http://www.mozlite.com
 * 
 * 配置类。
 * 
 * 最后修改：2011-10-29
 * ************************************************************/
namespace Mozlite.Common.Configuration
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    using System.Xml.Serialization;
    using System.Threading;
    using System.Text.RegularExpressions;
    using Mozlite.Cryptography;

    /// <summary>
    /// 配置类。
    /// </summary>
    [Serializable]
    public class SiteSettings : BaseObject
    {
        /// <summary>
        /// 初始化类型<see cref="T:Mozlite.Common.Configuration.SiteSettings"/>。
        /// </summary>
        public SiteSettings() {
            SmtpPort = 25;
            LogExpiredDays = 7;
            RequiresLogin = true;
            MaxTryTimes = 5;
            EachDequeueSize = 1000;
            FailureInterval = 60;
            SubjectEncoding = "UTF-8";
            BodyEncoding = "UTF-8";
            Language = Thread.CurrentThread.CurrentCulture.Name;
            EncryptType = EncryptionAlgorithm.MD5;
            AnonymousCookieName = "Mozlite.AnonymousCookie";
            AnonymousCookieExpiration = 20;
            AllowLogin = true;
            EnableBannedUsersToLogin = false;
            UniqueEmail = true;
            AccountActivation = Common.AccountActivation.Automatic;
            InitationKeyExpiredDays = 30;
            MaxFailedPasswordAnswerAttemptCount = 5;
            MaxFailedPasswordAttemptCount = 5;
            FailedPasswordAnswerAttemptWindowTimeout = 120;
            FailedPasswordAttemptWindowTimeout = 120;
            AvatarWidth = AvatarHeight = 84;
        }

        /// <summary>
        /// 从数据库中加载数据。
        /// </summary>
        /// <param name="reader">数据库读取器。</param>
        protected override void Load(IDataReader reader)
        {
            this.SettingsID = reader.GetInt32("SettingsID");
            this.SiteDomain = reader.GetString("Domain");
        }

        /// <summary>
        /// 获取当前配置实例对象。
        /// </summary>
        /// <param name="reader">数据库读取实例对象。</param>
        /// <returns>返回当前配置实例对象。</returns>
        public static SiteSettings TGet(IDataReader reader)
        {
            SiteSettings settings;
            try
            {
                settings = Globals.ConvertToObject<SiteSettings>(reader.GetString("SettingsXML"));
            }
            catch { settings = new SiteSettings(); }
            settings.LoadFromDataReader(reader);
            return settings;
        }

        /// <summary>
        /// 扩展属性数据库列名称。
        /// </summary>
        protected override string ExtendFieldName
        {
            get
            {
                return "ExtendSettings";
            }
        }

        /// <summary>
        /// 获取或设置网站设置的ID。
        /// </summary>
        [XmlIgnore]
        public int SettingsID { get; set; }

        /// <summary>
        /// 获取或设置域名。
        /// </summary>
        [XmlIgnore]
        public string SiteDomain { get; set; }

        private static readonly string defaultCacheKey = "SiteSettings::SettingsID.Default";
       
        /// <summary>
        /// 获取默认网站配置实例对象。
        /// </summary>
        public static SiteSettings Default
        {
            get
            {
                return Caches.Get<SiteSettings>(defaultCacheKey, () =>
                {
                    return Caches.Max(defaultCacheKey, ConfigurationDataProvider.Current.GetDefaultSettings());
                });
            }
        }

        private static readonly string cacheKey = "SiteSettings::SettingsID.";

        /// <summary>
        /// 获取当前应用程序配置实例对象。
        /// </summary>
        public static SiteSettings Current
        {
            get
            {
                if (!AppContext.Current.IsWebRequest)
                    return Default;
                return GetSiteSettings(AppContext.Current.Uri.DnsSafeHost);
            }
        }

        /// <summary>
        /// 从缓存中获取网站设置。
        /// </summary>
        /// <param name="domain">网站域名地址。</param>
        /// <returns>返回网站设置实例对象。</returns>
        public static SiteSettings GetSiteSettings(string domain) {
            domain = domain.ToLower();
            return Caches.Get<SiteSettings>(cacheKey + domain, Globals.MinuteSeconds, Globals.MinuteSeconds * 3, () =>
            {
                SiteSettings settings = ConfigurationDataProvider.Current.GetSiteSettings("." + domain);
                if (settings == null)
                    settings = Default;
                if (settings == null)
                {
                    settings = new SiteSettings();
                    settings.Save();
                }
                return settings;
            });
        }

        /// <summary>
        /// 保存当前配置实例。
        /// </summary>
        public void Save()
        {
            if (ConfigurationDataProvider.Current.SaveSiteSettings(this))
            {
                if (SiteDomain == null && AppContext.Current.SiteDomain != null)
                    this.SiteDomain = AppContext.Current.SiteDomain.Domain;
                if (SiteDomain != null)
                    Caches.Remove(cacheKey + this.SiteDomain.ToLower());
                Caches.Remove(defaultCacheKey);
            }
        }

        private string siteUrl;
        /// <summary>
        /// 获取当前配置的URL地址。
        /// </summary>
        public string SiteUrl
        {
            get
            {
                if (siteUrl == null)
                    siteUrl = "http://" + SiteDomain;
                return siteUrl;
            }
        }

        /// <summary>
        /// 获取或设置网站名称。
        /// </summary>
        public string SiteName { get; set; }

        /// <summary>
        /// 获取或设置时区ID。
        /// </summary>
        public string TimeZone { get; set; }

        /// <summary>
        /// 获取或设置ICP备案号。
        /// </summary>
        public string IcpCode { get; set; }

        /// <summary>
        /// 获取或设置分析统计代码。
        /// </summary>
        public string Analyzer { get; set; }

        /// <summary>
        /// 获取或设置关键字。
        /// </summary>
        public string MetaKeyWords { get; set; }

        /// <summary>
        /// 获取或设置网站描述。
        /// </summary>
        public string MetaDescription { get; set; }

        /// <summary>
        /// 获取或设置版权信息。
        /// </summary>
        public string Copyright { get; set; }

        /// <summary>
        /// 获取或设置日期格式。
        /// </summary>
        public string DateFormat { get; set; }

        /// <summary>
        /// 获取或设置时间格式。
        /// </summary>
        public string TimeFormat { get; set; }

        /// <summary>
        /// 获取或设置页面格式，需要服务器重启，只有默认网站才可以设置。
        /// </summary>
        public PageMode PageMode { get; set; }

        /// <summary>
        /// 获取或设置日志过期天数。
        /// </summary>
        public int LogExpiredDays { get; set; }

        /// <summary>
        /// 判断当前配置是否为默认配置。
        /// </summary>
        public bool IsDefault {
            get {
                return Default.SettingsID == Current.SettingsID;
            }
        }

        /// <summary>
        /// 获取日期和时间的格式。
        /// </summary>
        public string DateTimeFormat {
            get {
                return DateFormat + " " + TimeFormat;
            }
        }

        /// <summary>
        /// 默认模板。
        /// </summary>
        public string Theme { get; set; }

        /// <summary>
        /// 默认语言。
        /// </summary>
        public string Language { get; set; }

        #region mails
        /// <summary>
        /// 用于发送的电子邮件。
        /// </summary>
        public string WebMail { get; set; }

        /// <summary>
        /// SMTP主机。
        /// </summary>
        public string SmtpHost { get; set; }

        /// <summary>
        /// SMTP用户名。
        /// </summary>
        public string SmtpUserName { get; set; }

        /// <summary>
        /// SMTP密码。
        /// </summary>
        public string SmtpPassword { get; set; }

        /// <summary>
        /// 显示名称。
        /// </summary>
        public string DisplayName { get; set; }

        /// <summary>
        /// SMTP端口。
        /// </summary>
        public int SmtpPort { get; set; }

        /// <summary>
        /// 电子邮件文档编码。
        /// </summary>
        public string BodyEncoding { get; set; }

        /// <summary>
        /// 主题编码。
        /// </summary>
        public string SubjectEncoding { get; set; }

        /// <summary>
        /// 是否使用NTLM验证。
        /// </summary>
        public bool UseNtlmCredentials { get; set; }

        /// <summary>
        /// 是否需要登录。
        /// </summary>
        public bool RequiresLogin { get; set; }

        /// <summary>
        /// 最多尝试发送次数。
        /// </summary>
        public int MaxTryTimes { get; set; }

        /// <summary>
        /// 失败后继续发送的秒数。
        /// </summary>
        public int FailureInterval { get; set; }

        /// <summary>
        /// 每次从数据库中读取的记录数。
        /// </summary>
        public int EachDequeueSize { get; set; }
        #endregion

        #region users
        /// <summary>
        /// 获取或设置默认密码加密方式。
        /// </summary>
        public EncryptionAlgorithm EncryptType { get; set; }
        /// <summary>
        /// 匿名Cookie名称。
        /// </summary>
        public string AnonymousCookieName { get; set; }
        /// <summary>
        /// 匿名Cookie过期时间（分钟）。
        /// </summary>
        public int AnonymousCookieExpiration { get; set; }
        /// <summary>
        /// 获取或设置Cookie域。
        /// </summary>
        public string CookieDomain { get; set; }
        /// <summary>
        /// 获取或设置注册时是否需要安全信息（问题/答案）。
        /// </summary>
        public bool QuestionAnswer { get; set; }
        /// <summary>
        /// 获取或设置是否允许用户登录。
        /// </summary>
        public bool AllowLogin { get; set; }
        /// <summary>
        /// 获取或设置是否禁止用户登录。
        /// </summary>
        public bool EnableBannedUsersToLogin { get; set; }
        /// <summary>
        /// 获取或设置头像图片后缀名。
        /// </summary>
        public string AllowAvatarExtensions { get; set; }
        /// <summary>
        /// 获取或设置头像图片长度。
        /// </summary>
        public int AvatarWidth { get; set; }
        /// <summary>
        /// 获取或设置头像图片高度。
        /// </summary>
        public int AvatarHeight { get; set; }
        /// <summary>
        /// 获取或设置用户名正则表达式。
        /// </summary>
        public string UserNameRegex { get; set; }
        /// <summary>
        /// 获取或设置用户名正则表达式的描述信息，用于显示在注册的时候。
        /// </summary>
        public string UserNameRegexDescription { get; set; }
        /// <summary>
        /// 获取或设置Email是否唯一。
        /// </summary>
        public bool UniqueEmail { get; set; }
        /// <summary>
        /// 判断用户名的格式。
        /// </summary>
        /// <param name="userName">用户名称。</param>
        /// <returns>格式符合，返回<c>true</c>。</returns>
        public static bool IsUserNameValid(string userName)
        {
            if (string.IsNullOrEmpty(Default.UserNameRegex))
                return false;
            return userName.IsMatched(Default.UserNameRegex, RegexOptions.Compiled | RegexOptions.IgnoreCase);
        }
        /// <summary>
        /// 获取或设置密码正则表达式。
        /// </summary>
        public string PasswordRegex { get; set; }
        /// <summary>
        /// 获取或设置密码正则表达式描述信息，用于修改密码或注册账号时使用。
        /// </summary>
        public string PasswordRegexDescription { get; set; }
        /// <summary>
        /// 判断密码的格式。
        /// </summary>
        /// <param name="password">密码。</param>
        /// <returns>格式符合，返回<c>true</c>。</returns>
        public static bool IsPasswordValid(string password)
        {
            if (string.IsNullOrEmpty(Default.PasswordRegex))
                return false;
            return password.IsMatched(Default.PasswordRegex, RegexOptions.Compiled);
        }
        /// <summary>
        /// 获取或设置是否发生电子邮件。
        /// </summary>
        public bool SendEmail { get; set; }
        /// <summary>
        /// 获取或设置帐号生效方式。
        /// </summary>
        public AccountActivation AccountActivation { get; set; }
        /// <summary>
        /// 获取或设置邀请码过期天数。
        /// </summary>
        public int InitationKeyExpiredDays { get; set; }
        /// <summary>
        /// 获取或设置最大秘密验证失败次数。
        /// </summary>
        public int MaxFailedPasswordAttemptCount { get; set; }
        /// <summary>
        /// 获取或设置最大秘密安全验证失败次数。
        /// </summary>
        public int MaxFailedPasswordAnswerAttemptCount { get; set; }
        /// <summary>
        /// 获取或设置最大秘密验证失败延迟数(分钟)。
        /// </summary>
        public int FailedPasswordAttemptWindowTimeout { get; set; }
        /// <summary>
        /// 获取或设置最大秘密安全验证失败延迟数(分钟)。
        /// </summary>
        public int FailedPasswordAnswerAttemptWindowTimeout { get; set; }
        #endregion

        /// <summary>
        /// 获取或设置禁用名称。
        /// </summary>
        public string DenyNames { get; set; }

        /// <summary>
        /// 判断用户名是否被禁用。
        /// </summary>
        /// <param name="userName">用户名称。</param>
        /// <returns>返回是否被禁用。</returns>
        public static bool IsDisallowed(string userName)
        {
            string names = Default.DenyNames;
            if (string.IsNullOrEmpty(names))
                return false;
            foreach (var name in names.Split<string>("\r\n"))
            {
                if (name.IsMatched(Regex.Escape(name).Replace("*", ".*"), RegexOptions.IgnoreCase | RegexOptions.Compiled))
                    return true;
            }
            return false;
        }
    }
}
